﻿using System;
using System.Collections;
using System.Linq;
using System.Text;


namespace P2
{
    class lex
    {
        static int contadorDeEscopos = 0;
        static int contadorDeFuncoes = 0;
        static int indiceNaTabelaDeSimbolos = 0;
        private Hashtable tabelaDeSimbolos;
        public ArrayList AnalisaEntrada(string s)
        {
            Hashtable tabDeSimbs = new Hashtable();
            Hashtable linTabSimb;
            ArrayList fluxoDeTk = new ArrayList(); 
            int state = 0; 
            Tk token;
            Tk tk;
            Tk tk_fun;
            token = null;
            StringBuilder identificador = new StringBuilder();
            StringBuilder numero = new StringBuilder();
            char[] programa = s.ToCharArray();
            string[] palavrasReservadas =
            {   "fun", 
                "return",
	            "funend",
	            "while",
	            "do",
	            "whilend",
                "for",
                "forend",
                "if",
                "then",
                "else",
                "ifend",
                "switch",
                "case",
                "break",
                "switchend",
                "print",
                "scan",
                "call",
                "program",
                "declare",
                "begin",
                "programend",
	            "int",
	            "bool",
	            "char",
                "And",
                "Or"
            };
            char comparador; // char pra comparar no automato
            char lookAhead; // o look-ahead
            int i = 0; // percorredor de programa

            
while (i < programa.Length)
            {
                comparador = programa[i];
                if (i < (programa.Length - 1))
                {
                    lookAhead = programa[i + 1];
                }
                else
                {
                    lookAhead = programa[i];
                }

                if (state == 0)
                {
                    if ((Convert.ToInt32('a') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('z')) || ((Convert.ToInt32('A') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('Z'))))
                    {
                        state = 10;
                        identificador.Append(comparador);
                        i++;
                    }
                    else if (((Convert.ToInt32('0') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('9'))))
                    {
                        state = 1;
                        numero.Append(comparador);
                        i++;
                    }
                    else if (comparador == '+' || comparador == '-' || comparador == '*' || comparador == '/')
                    {
                        state = 0;
                        token = new Tk("op", comparador.ToString());
                        fluxoDeTk.Add(token);
                        i++;
                    }
                    else if (comparador == '(' || comparador == ')' || comparador == '[' || comparador == ']')
                    {
                        state = 0;
                        token = new Tk("delim", comparador.ToString());
                        fluxoDeTk.Add(token);
                        i++;
                    }
                    else if (comparador == '<')
                    {
                        if (lookAhead == '>' || lookAhead == '=')
                        {
                            state = 0;
                            token = new Tk("comp", comparador.ToString() + lookAhead.ToString());
                            fluxoDeTk.Add(token);
                            i=i+2;
                        }
                        else
                        {
                            state = 0;
                            token = new Tk("comp", comparador.ToString());
                            fluxoDeTk.Add(token);
                            i++;
                        }
                    }
                    else if (comparador == '>') 
                    {
                        if (lookAhead == '=')
                        {
                            state = 0;
                            token = new Tk("comp", comparador.ToString() + lookAhead.ToString());
                            fluxoDeTk.Add(token);
                            i=i+2;
                        }
                        else
                        {
                            state = 0;
                            token = new Tk("comp", comparador.ToString());
                            fluxoDeTk.Add(token);
                            i++;
                        }
                    
                    }
                    else if(comparador == '&')
                    {
                        state = 23;
                        i++;
                    }
                    else if(comparador == '=')
                    {
                        if (lookAhead == '=')
                        {
                            state = 0;
                            token = new Tk("comp", comparador.ToString() + lookAhead.ToString());
                            fluxoDeTk.Add(token);
                            i = i + 2;
                        }
                        else
                        {
                            state = 0;
                            token = new Tk("atrib", comparador.ToString());
                            fluxoDeTk.Add(token);
                            i++;
                        }
                    }
                    else if (char.IsWhiteSpace(comparador) || comparador =='\r' || comparador == '\n')
                    {
                        state = 0;
                        i++;
                    }
                    else
                    {
                        state = 0;
                        token = new Tk("outro", comparador.ToString());
                        fluxoDeTk.Add(token);
                        i++;
                    }
                }
                else if (state == 10)
                {
                    if ((Convert.ToInt32('a') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('z')) || ((Convert.ToInt32('A') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('Z'))) || ((Convert.ToInt32('0') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('9'))))
                    {
                        state = 10;
                        identificador.Append(comparador);
                        i++;
                    }
                    else
                    {// aqui ele trata o token de ID e NOME

                        if (palavrasReservadas.Contains(identificador.ToString()))
                        {
                            if (identificador.ToString() == "fun") 
                            {
                                contadorDeFuncoes++;
                                contadorDeEscopos = contadorDeFuncoes;
                            }
                            else if (identificador.ToString() == "funend")
                            {
                                contadorDeEscopos = 0;
                            }
                            state = 0;
                            token = new Tk("pr", identificador.ToString());
                            fluxoDeTk.Add(token);   
                            identificador.Remove(0, identificador.Length);
                        }

                        else if (comparador == '[') 
                        {
                            state = 0;
                            token = new Tk("nome", identificador.ToString());
                            fluxoDeTk.Add(token);
                            identificador.Remove(0, identificador.Length);
                        }

                        else
                        {
                            tk = (Tk) fluxoDeTk[fluxoDeTk.Count-1];
                            tk_fun = (Tk)fluxoDeTk[fluxoDeTk.Count - 2];
                            linTabSimb = new Hashtable();
                            if (tk.getValor() == "int" || tk.getValor() == "bool" || tk.getValor() == "char") 
                            {
                                if (tk_fun.getValor() == "fun")
                                {
                                    linTabSimb.Add("funcao", true);
                                }
                                else 
                                {
                                    linTabSimb.Add("funcao", false);
                                }
                                linTabSimb.Add("tipo", tk.getValor());
                                linTabSimb.Add("valor",identificador.ToString());
                                if (!tabDeSimbs.ContainsKey(identificador.ToString() + "." + contadorDeEscopos.ToString()))
                                {
                                    tabDeSimbs.Add(identificador.ToString() + "." + contadorDeEscopos.ToString(), linTabSimb);
                                }
                            }
                            state = 0;

                            token = new Tk("id", identificador.ToString()  + "." + contadorDeEscopos.ToString());
                            fluxoDeTk.Add(token);
                            identificador.Remove(0, identificador.Length);
                        }
                    }
                }
                else if (state == 1) 
                {
                    if (((Convert.ToInt32('0') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('9'))))
                    {
                        state = 1;
                        numero.Append(comparador);
                        i++;
                    }
                    else if ((Convert.ToInt32('a') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('z')) || ((Convert.ToInt32('A') <= Convert.ToInt32(comparador)) && (Convert.ToInt32(comparador) <= Convert.ToInt32('Z'))))
                    {
                        Console.Beep(1000,3000);
                        Console.WriteLine("Não pode colocar letra em número!!");
                        Console.ReadLine();
                        Console.Beep(1000, 250);
                        Environment.Exit(666);
                    }
                    else
                    {
                        state = 0;
                        token = new Tk("num", numero.ToString());
                        fluxoDeTk.Add(token);   
                        numero.Remove(0, numero.Length);
                    }
                }
                else if (state == 23) 
                {
                    if (comparador == '&')
                    {
                        state = 0;
                    }
                    i++;
                }
            }//fim do while
            tabelaDeSimbolos = tabDeSimbs;
            return fluxoDeTk;
        }
        public Hashtable GetTabSimb() 
        {
            return tabelaDeSimbolos;
        }
    }
}